// -----------------------------
// Author: 		Dhaenens Gert 
// Creation: 	8/4/2013 3:34:21 PM				
// -----------------------------

#ifndef _LuaStack_h
#define _LuaStack_h

#include "ObjectLuaCommon.h"

#include "LuaObject.h"
#include "LuaStackDump.h"
#include "LuaTable.h"

namespace ObjectLua
{

	class OBJECTLUA LuaStack : public LuaObject
	{
	public:
		typedef int (*CFunc)(lua_State*);

		LuaStack(Lua* lpLua);
		virtual ~LuaStack();

		/*
		//	Get a Stack Dump
		*/
		LuaStackDump	stackDump();
		/*
		//	Pop a value from the stack
		*/
		void			pop(int idx);
		/*
		//	Get an up value index
		//	linked to a closure value
		//	@ idx : up value index
		*/
		static int		upValueIndex(int idx);
		/*
		//	Set the Table to link
		//	@ idx : index
		*/
		void			setTable(int idx);
		/*
		//	Set the Metatable to link
		//	@ idx : index
		*/
		void			setMetaTable(int idx);
		/*
		//	Set the function up value
		*/
		void			setupvalue(int idx, int upIdx);
		/*
		//	Get the top index
		*/
		int				getTop();
		/*
		//	Request User Data
		//	@ size : size of the data block
		*/
		void*			requestUserData(size_t size);
		/* 
		//	Request Meta Table
		//	@ lpName : name of the meta table
		*/
		void			requestMetaTable(const char* lpName);
		/*
		//	Request a Table
		*/
		void			requestTable();
		/*
		//	Register a Table of Functions
		//	To the Table
		//	@ funcCount : amount of functions
		//	@ functions : function table
		*/
		void			registerFunctions(const int funcCount, LuaReg functions[]);



		/*
		//	Push an integer onto the stack
		//	@ i : integer to be pushed
		*/
		void			pushInteger(int i);
		/*
		//	Push a bool onto the stack
		//	@ b : bool to be pushed
		*/
		void			pushBool(bool b);
		/*
		//	Push a number onto the stack
		//	@ d : number to be pushed
		*/
		void			pushNumber(double d);
		/*
		//	Push a string onto the stack
		//	@ lpStr : null-terminated string to be pushed
		*/
		void			pushString(const char* lpStr);
		/*
		//	Push Light User Data onto the Stack
		//	@ lpData : data to be pushed
		*/
		void			pushLightUserData(void* lpData);
		/*
		//	Push a closure onto the Stack
		//	@ lpFunc : Function to bind closure to
		//	@ nargs : amount of arguments in the closure
		*/
		void			pushClosure(int (*lpFunc)(lua_State*), int nargs);
		/*
		//	Push a Function
		//	@ lpFunc : Function to push
		*/
		void			pushFunction(int (*lpFunc)(lua_State*));
		/*
		//	Push a value onto the stack
		//	Duplicates the value
		//	@ idx : Index of the value
		*/
		void			pushValue(int idx);


		/*
		//	Set a Field on the Stack
		//	@ idx : index
		//	@ name : name of the field
		*/
		void			setField(int idx, const char* name);


		/*
		//	Set a Global Value
		//	@ name : name of the field
		*/
		void			setGlobal(const char* name);


		/*
		//	Get a Global Value
		//	@ name : name of the Global
		*/
		void			getGlobal(const char* name);
		/*
		//	Get an integer from the stack
		//	@ idx : stack index
		*/
		int				getInteger(int idx);
		/*
		//	Get a bool from the stack
		//	@ idx : stack index
		*/
		bool			getBool(int idx);
		/*
		//	Get a number from the stack
		//	@ idx : stack index
		*/
		double			getNumber(int idx);
		/*
		//	Get a null-terminated string
		//	from the stack
		//	@ idx : stack index
		*/
		const char*		getString(int idx);
		/*
		//	Get UserData from the Stack
		//	@ idx : stack index
		*/
		void*			getUserData(int idx);
		/*
		//	Get a field from the table
		//	on the stack
		//	@ idx : index of the table
		//	@ name : name of the field
		*/
		void			getField(int idx, const char* name);
		/*
		//	Get a Function from the stack
		//	@ idx : index of the function
		*/
		CFunc			getFunction(int idx);
		/*
		//	Get an Up Value
		*/
		void			getupvalue(int idx, int UpIdx);

		/*
		//	Check if userdata with associated
		//	metatable name
		//	@ idx : stack index
		//	@ name : metatable name
		*/
		void*			checkUserData(int idx, const char* name);
		/*
		//	Get a metatable from
		//	the stack
		//	@ idx : stack index
		*/
		LuaTable		getMetaTable(int idx);

		/*
		//	Check if a value at a given
		//	index on the stack is userdata
		*/
		bool			isUserData(int idx);
		/*
		//	Check if a value at a given
		//	index on the stack is an int
		*/
		bool			isInteger(int idx);
		/*
		//	Check if a value at a given
		//	index on the stack is a number
		*/
		bool			isNumber(int idx);
		/*
		//	Check if a value at a given
		//	index on the stack is a string
		*/
		bool			isString(int idx);
		/*
		//	Check if a value at a given
		//	index on the stack is a boolean
		*/
		bool			isBoolean(int idx);
		/*
		//	Check if a value at a given
		//	indexs on the stack is nil
		*/
		bool			isNil(int idx);
		/*
		//	Checks if a value at a given
		//	index on the stack is a table
		*/
		bool			isTable(int idx);
		/*
		//	Checks if a value at a given
		//	index on the stack is a function
		*/
		bool			isFunction(int idx);
		/*
		//	Checks if a value at a given
		//	index on the stack is a certain type
		*/		

		/*
		//	Load a File onto the Stack
		//	@ lpFile : path to file
		*/
		void			loadFile(const char* lpFile);

		/*
		//	Call a function from the Stack
		//	@ nargs : argument count
		//	@ nreturn : return count
		*/
		void			pcall(int nargs, int nreturn);

		/*
		//	Static Version of getUserData
		//	Used for in callbacks since
		//	We don't have access to the Lua object yet
		//	@ lpState : lua state
		//	@ idx : stack index
		*/
		static void*	getUserData(lua_State* lpState, int idx);
		/*
		//	Static Version of checkUserData
		//	Used for in callbacks since
		//	We don't have access to the Lua object yet
		//	@ lpState : lua state
		//	@ idx : stack index
		//	@ name : metatable name
		*/
		static void*	checkUserData(lua_State* lpState, int idx, const char* name);
	
	private:
	
		LuaStack(const LuaStack& refLuaStack);
		LuaStack& operator=(const LuaStack& refLuaStack);
	};

}

#endif